package cn.dduan.fool.reflection;

import cn.dduan.fool.entity.HomeEntity;
import lombok.SneakyThrows;

/**
 * 反射机制
 * <p>
 * 作用：
 * 1. 运行时动态获取类的信息：在编写代码时，对于类的信息是必须在编译时确定的，但在运行时，有时需要根据某些条件，动态获取某个类的信息，这时就可以使用Java中的反射机制
 * 2. 动态生成对象：反射机制可以在运行时生成对象，这样就可以根据参数的不同，动态的创建不同的类的实例对象
 * 3. 动态调用方法：通过反射机制可以调用类中的方法，不论这些方法是否是公共的，也不论这些方法的参数个数和类型是什么，反射机制都具有这样的能力
 * 4. 动态修改属性：利用反射机制可以获取到类中的所有成员变量，并可以对其进行修改
 * 5. 实现动态代理：利用反射机制可以实现代理模式，通过代理对象完成原对象对某些方法的调用，同时也可以在这些方法的调用前后做一些额外的处理
 * <p>
 * 优点：
 * 1. 增加灵活性和扩展性：使用反射机制可以在程序运行时动态加载、修改、创建、调用类和方法等，从而增加了程序的灵活性和可扩展性
 * 2. 提高代码的通用性：通过反射机制可以动态的获取类信息，从而可以编写通用的代码，使得不同的类能够以相同的方式来处理
 * 3. 规范代码结构：反射机制可以使代码结构清晰明了，减少了代码中的冗余部分
 * 4. 实现框架和插件：反射机制在很多框架和插件中都有广泛的应用，比如Spring框架、JUnit测试框架等
 * 5. 动态代理：反射机制的另一个重要应用是实现动态代理，可以在不修改原来代码的情况下，通过代理对象对原对象的方法进行增强
 * <p>
 * 缺点：
 * 1. 性能开销大：反射操作涉及到动态解析和调用，比直接调用方法和访问字段的性能要低
 * 2. 安全性问题：反射机制可以绕过 Java 的访问权限检查，可能会破坏类的封装性，带来安全隐患
 * 3. 代码可读性和维护性差：反射代码通常比较复杂，不易理解和维护
 * <p>
 * 获取Class的三种方式：
 * 1. Class.forname - 应用在jdbc数据库连接中
 * 2. 类实例.getclass() - 通用增删改
 * 3. 类名.class - 通用查询
 * <p>
 * 反射的应用场景：
 * 1. 动态加载类和调用方法
 * 2. 框架开发
 * 3. 注解处理
 * 4. 动态代理
 * 5. 序列化和反序列化
 * 6. 访问私有成员
 * 7. 插件化架构
 * 8. 泛型类型擦除后的类型信息获取
 * 9. 工具类库
 * 10. 调试和测试
 * 11. 动态生成代码
 * 12. 兼容性处理
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/14
 */
public class MyReflection {
    @SneakyThrows
    public static void main(String[] args) {

        /**
         * 获取Class的三种方式
         * 1. Class.forname
         * 2. 类实例.getclass()
         * 3. 类名.class
         */
        Class<?> aClass = Class.forName("cn.dduan.fool.entity.HomeEntity");

        HomeEntity home = new HomeEntity("呼和浩特市", "dduan的家");
        Class clas = home.getClass();

        Class<HomeEntity> homeEntityClass = HomeEntity.class;

        // 获取包名
        System.out.println("获取包名：" + clas.getPackage().getName());
        // 获取类名
        System.out.println("获取类名：" + clas.getSimpleName());
        // 获取完整类名
        System.out.println("获取完整类名：" + clas.getName());

        // 获取所有公开的成员变量，包括继承变量
        System.out.println("获取所有公开的成员变量,包括继承变量：" + clas.getFields());
        System.out.println("获取所有公开的成员变量,包括继承变量：" + clas.getField("name"));
        // 获取本类定义的成员变量,包括私有,但不包括继承的变量
        System.out.println("获取本类定义的成员变量,包括私有,但不包括继承的变量：" + clas.getDeclaredFields());
        System.out.println("获取本类定义的成员变量,包括私有,但不包括继承的变量：" + clas.getDeclaredField("addr"));
        System.out.println("获取本类定义的成员变量,包括私有,但不包括继承的变量：" + clas.getDeclaredField("name"));

        // 获取构造方法定义信息
        System.out.println("获取所有的公开的构造方法：" + clas.getConstructors());
        System.out.println("获取公开的构造方法：" + clas.getConstructor(String.class, String.class));
        // 获取所有的构造方法,包括私有
        System.out.println("获取所有的构造方法,包括私有:" + clas.getDeclaredConstructors());
        System.out.println("获取所有的构造方法,包括私有:" + clas.getDeclaredConstructor(String.class, String.class));

    }
}